﻿CREATE FUNCTION QIC.InterfaceFactory_FN (@ConfigName VARCHAR(50), @InterfaceId INT)
RETURNS NVARCHAR(MAX)
AS
BEGIN

	DECLARE @Retval VARCHAR(MAX)
	DECLARE @Parameters VARCHAR(MAX)
	DECLARE @ReturnToken VARCHAR(MAX)
	DECLARE @ObjectName VARCHAR(MAX)
	DECLARE @HasDelegateName BIT
	DECLARE @Implementation VARCHAR(MAX)
	DECLARE @Declare VARCHAR(MAX)
	DECLARE @DelegateName VARCHAR(50)
	DECLARE @Returns VARCHAR(MAX)
	DECLARE @HasAspect BIT
	DECLARE @UseReturnToken BIT
	DECLARE @HasCalls BIT
	DECLARE @HasDefault BIT
	DECLARE @DelegateImplementation VARCHAR(MAX)

	DECLARE @Token QIC.TokenTable
	DECLARE @Delegate TABLE (DelegateId INT, InterfaceId INT, DelegateName VARCHAR(50), InterfaceType VARCHAR(50), TokenMap VARCHAR(50), CallFactory VARCHAR(50))
	DECLARE @Aspect TABLE (AspectId INT, InterfaceId INT, DelegateName VARCHAR(50), ActionName VARCHAR(50), AspectReturnToken VARCHAR(50), SortOrder INT, AspectType VARCHAR(50), TokenMap VARCHAR(50), CallFactory VARCHAR(50))
	DECLARE @Call TABLE (Id INT IDENTITY(1,1), DelegateName VARCHAR(50), Call VARCHAR(MAX), ActionName VARCHAR(50))

	SET @ReturnToken = '@InterfaceReturn'

	INSERT INTO @Aspect (InterfaceId,AspectId,DelegateName,ActionName,AspectReturnToken,SortOrder,AspectType, TokenMap, CallFactory)
	SELECT InterfaceId,AspectId,DelegateName, ActionName, AspectReturnToken,SortOrder,AspectType,TokenMap, CallFactory
	FROM QIC.Aspect_(@ConfigName) aspect
	WHERE InterfaceId = @InterfaceId
	AND AspectId <> @InterfaceId

	IF @@ROWCOUNT <> 0 SET @HasAspect = 1
	IF @HasAspect = 1 SET @UseReturnToken = 1

	INSERT INTO @Delegate (InterfaceId,DelegateId,DelegateName,InterfaceType,TokenMap, CallFactory)
	SELECT InterfaceId,DelegateId, DelegateName, InterfaceType, TokenMap, CallFactory
	FROM QIC.Delegate_(@ConfigName) delegate
	WHERE InterfaceId = @InterfaceId

	INSERT INTO @Token (ObjectId, PropertyId, PropertyName, UserTypeId, Precision, Scale, MaxLength, IsOutPut, IsReadOnly)
	SELECT distinct parameters.object_id, parameters.parameter_id, case parameters.parameter_id WHEN 0 THEN @ReturnToken ELSE parameters.name END, parameters.user_type_id , parameters.precision, parameters.scale, parameters.max_length, parameters.is_output, parameters.is_readonly
	FROM sys.parameters parameters
	WHERE parameters.object_id = @InterfaceId

	INSERT INTO @Token (ObjectId, PropertyId, PropertyName, UserTypeId, Precision, Scale, MaxLength, IsOutPut, IsReadOnly)
	SELECT distinct parameters.object_id, parameters.parameter_id, case parameters.parameter_id WHEN 0 THEN @ReturnToken ELSE parameters.name END, parameters.user_type_id, parameters.precision, parameters.scale, parameters.max_length, parameters.is_output, parameters.is_readonly
	FROM sys.parameters parameters
	INNER JOIN @Delegate delegate
		ON delegate.DelegateId = parameters.object_id

	IF EXISTS (select * from @Token where PropertyName = '@DelegateName') 
	BEGIN
		SET @HasDelegateName = 1
	END
	ELSE
	BEGIN
		SET @HasDelegateName = 0
	END
	
	INSERT INTO @Token (ObjectId, PropertyId, PropertyName, UserTypeId, Precision, Scale, MaxLength, IsOutPut, IsReadOnly)
	SELECT distinct parameters.object_id, parameters.parameter_id, case parameters.parameter_id WHEN 0 THEN @ReturnToken ELSE parameters.name END, parameters.user_type_id , parameters.precision, parameters.scale, parameters.max_length, parameters.is_output, parameters.is_readonly
	FROM sys.parameters parameters
	INNER JOIN @Aspect aspect
		ON aspect.AspectId = parameters.object_id
	WHERE parameters.parameter_id > 0

	INSERT INTO @Token (ObjectId, PropertyId, PropertyName, UserTypeId, Precision, Scale, MaxLength, IsOutPut, IsReadOnly)
	SELECT distinct aspect.AspectId, returntoken.PropertyId, aspect.AspectReturnToken, returntoken.UserTypeId, returntoken.Precision, returntoken.Scale, returntoken.MaxLength, returntoken.IsOutPut, returntoken.IsReadOnly
	FROM @Aspect aspect
	CROSS APPLY QIC.ObjectReturnToken(AspectId) returntoken

	IF @HasDelegateName = 0 AND EXISTS (select * from @Token where PropertyName = '@DelegateName' and (PropertyId = 0 or IsOutPut = 1)) 
	BEGIN
		SET @HasDelegateName = 1
	END

	SELECT @ObjectName = QIC.ObjectName(@InterfaceId)

	IF @HasAspect = 1
	BEGIN
		INSERT INTO @Call (DelegateName,Call,ActionName)
		SELECT aspect.DelegateName, QIC.CallFactory(@ConfigName, @Token, @InterfaceId, aspect.AspectId, aspect.AspectReturnToken, aspect.TokenMap, CASE WHEN aspect.DelegateName IN ('DEFAULT','') OR @HasDelegateName = 0 THEN 1 ELSE 2 END, '',aspect.CallFactory), aspect.ActionName
		FROM @Aspect aspect
		WHERE aspect.ActionName = 'BEFORE'	
		ORDER BY aspect.SortOrder	
	END
	
	INSERT INTO @Call (DelegateName,Call,ActionName)
	SELECT delegate.DelegateName, QIC.CallFactory(@ConfigName, @Token, @InterfaceId, delegate.DelegateId, CASE @UseReturnToken WHEN 1 THEN @ReturnToken ELSE '' END, delegate.TokenMap, CASE WHEN delegate.DelegateName IN ('DEFAULT') OR @HasDelegateName = 0 THEN 1 ELSE 2 END, delegate.DelegateName, delegate.CallFactory),'DELEGATE'
	FROM @Delegate delegate

	IF @@ROWCOUNT > 0 SET @HasCalls = 1

	IF @HasAspect = 1
	BEGIN
		INSERT INTO @Call (DelegateName,Call,ActionName)
		SELECT aspect.DelegateName, QIC.LB() + QIC.CallFactory(@ConfigName, @Token, @InterfaceId, aspect.AspectId, aspect.AspectReturnToken, aspect.TokenMap, CASE WHEN aspect.DelegateName IN ('DEFAULT') OR @HasDelegateName = 0 THEN 1 ELSE 2 END,'', aspect.CallFactory), aspect.ActionName
		FROM @Aspect aspect
		WHERE aspect.ActionName = 'AFTER'	
		ORDER BY aspect.SortOrder	
	END

	IF EXISTS(SELECT * FROM @Call WHERE DelegateName = 'DEFAULT') SET @HasDefault = 1

	SET @Parameters = ''
	SET @Implementation = ''
	SET @Returns = ''

	SELECT @Parameters = QIC.InterfaceTokenDefine(@Token, @InterfaceId)

	SELECT @Returns = QIC.TokenDefine('', UserTypeId, Precision, Scale, MaxLength, 0, 0)
	FROM @Token 
	WHERE ObjectId = @InterfaceId
	AND PropertyId = 0

	IF ISNULL(@UseReturnToken,0) = 0
	BEGIN
		DELETE @Token WHERE PropertyId = 0
	END

	SELECT @Declare = QIC.TokenDeclare(@Token,@InterfaceId, 1)

	BEGIN
		SET @DelegateImplementation = ''

		SELECT @DelegateImplementation += Call + QIC.LB()
		FROM @Call
		WHERE DelegateName = '' and ActionName = 'BEFORE'
		ORDER BY Id

		IF @DelegateImplementation <> '' SET @Implementation += @DelegateImplementation + QIC.LB()
	END


	DECLARE callCursor CURSOR LOCAL FAST_FORWARD FOR
	SELECT distinct DelegateName FROM @Call WHERE DelegateName not in ('','DEFAULT') and @HasDelegateName = 1

	OPEN callCursor

	WHILE(1=1)
	BEGIN
		FETCH NEXT FROM callCursor INTO @DelegateName
		IF @@FETCH_STATUS <> 0 BREAK

		SET @DelegateImplementation = ''

		SET @DelegateImplementation += QIC.Indent(1) + 'IF @DelegateName=' + QUOTENAME(@DelegateName,'''') + QIC.LB()
		SET @DelegateImplementation += QIC.Indent(1) + 'BEGIN' + QIC.LB()

		SELECT @DelegateImplementation += Call + QIC.LB()
		FROM @Call
		WHERE DelegateName = @DelegateName
		ORDER BY Id

		SELECT @DelegateImplementation += Call + QIC.LB()
		FROM @Call
		WHERE DelegateName = '' and ActionName = 'AFTER'
		ORDER BY Id

		IF @UseReturnToken = 1
		BEGIN
			SET @DelegateImplementation += QIC.Indent(2) + 'RETURN ' + @ReturnToken + QIC.LB()
		END
		SET @DelegateImplementation += QIC.Indent(1) + 'END'+ QIC.LB()
		SET @Implementation += @DelegateImplementation

	END

	CLOSE callCursor
	DEALLOCATE callCursor

	SET @Implementation += QIC.Indent(1) + '--DEFAULT' + QIC.LB()
	IF @HasDefault = 1
	BEGIN
		SELECT @Implementation += Call + QIC.LB()
		FROM @Call
		WHERE DelegateName = 'DEFAULT'
		ORDER BY Id

		SELECT @Implementation += Call + QIC.LB()
		FROM @Call
		WHERE DelegateName = '' and ActionName = 'AFTER'
		ORDER BY Id
	END
	IF @UseReturnToken = 1
	BEGIN
		SET @Implementation += QIC.Indent(1) + 'RETURN ' + @ReturnToken + QIC.LB()
	END
	ELSE
	BEGIN
		IF ISNULL(@HasDefault,0) = 0
		BEGIN
			SET @Implementation += QIC.Indent(1) + 'RETURN NULL' + QIC.LB()
		END
	END

	SET @Retval = 'ALTER FUNCTION ' + @ObjectName + ' (' + @Parameters + ')' + QIC.LB()
	SET @Retval += 'RETURNS ' + @Returns + QIC.LB()
	SET @Retval += 'AS' + QIC.LB()
	SET @Retval += 'BEGIN' + QIC.LB()
	IF @Declare <> ''
	BEGIN
		SET @Retval += @Declare + QIC.LB()
	END

	SET @Retval += ISNULL(QIC.LB() + @Implementation +QIC.LB(),'')
	SET @Retval += 'END' 


	RETURN @Retval

END
